package com.yilian.bionio;

import java.io.*;
import java.net.*;
import java.util.concurrent.*;

/**
 * accept()阻塞机制演示类
 * 
 * 这个类专门演示accept()的阻塞机制和线程模型：
 * 1. 单线程accept()阻塞演示 - 可以依次接受多个连接，但处理时会阻塞
 * 2. 多线程accept()阻塞演示 - accept()和处理客户端分离
 * 3. 阻塞vs非阻塞的区别
 * 
 * @author 练习项目
 * @version 1.0
 */
public class AcceptBlockingDemo {
    
    private static final int PORT = 8889;
    
    public static void main(String[] args) {
        System.out.println("=== accept()阻塞机制演示 ===\n");
        
        // 1. 演示单线程accept()阻塞
        //demonstrateSingleThreadAccept();
        
        // 2. 演示多线程accept()阻塞
        demonstrateMultiThreadAccept();
        
        System.out.println("\n=== accept()阻塞机制演示完成 ===");
    }
    
    // ==================== 单线程accept()阻塞演示 ====================
    
    /**
     * 演示单线程accept()的阻塞特性
     * 可以依次接受多个连接，但处理时会阻塞accept()
     */
    private static void demonstrateSingleThreadAccept() {
        System.out.println("--- 单线程accept()阻塞演示 ---");
        System.out.println("特点：可以依次接受多个连接，但处理时会阻塞accept()");
        
        // 启动单线程服务器
        SingleThreadServer server = new SingleThreadServer(PORT);
        server.start();
        
        try {
            // 等待服务器启动
            Thread.sleep(2000);
            
            System.out.println("\n1. 依次连接3个客户端...");
            
            // 创建3个客户端，依次连接
            for (int i = 1; i <= 3; i++) {
                final int clientId = i;
                new Thread(() -> {
                    try {
                        System.out.println("   客户端" + clientId + "开始连接...");
                        connectClient("客户端" + clientId, "Hello from Client " + clientId);
                    } catch (Exception e) {
                        System.err.println("   客户端" + clientId + "异常: " + e.getMessage());
                    }
                }).start();
                
                // 稍微错开连接时间
                Thread.sleep(1000);
            }
            
            // 等待所有客户端完成
            Thread.sleep(15000);
            
            // 停止服务器
            server.stop();
            
        } catch (InterruptedException e) {
            System.err.println("演示被中断: " + e.getMessage());
        }
    }
    
    // ==================== 多线程accept()阻塞演示 ====================
    
    /**
     * 演示多线程accept()的阻塞特性
     * 优势：accept()和处理客户端分离，可以同时接受多个连接
     */
    private static void demonstrateMultiThreadAccept() {
        System.out.println("\n--- 多线程accept()阻塞演示 ---");
        System.out.println("优势：accept()和处理客户端分离，可以同时接受多个连接");
        
        // 启动多线程服务器
        MultiThreadServer server = new MultiThreadServer(PORT + 1);
        server.start();
        
        try {
            // 等待服务器启动
            Thread.sleep(2000);
            
            System.out.println("\n1. 同时连接多个客户端...");
            
            // 创建多个客户端线程
            Thread client1 = new Thread(() -> connectClient("客户端1", "Hello from Client 1"));
            Thread client2 = new Thread(() -> connectClient("客户端2", "Hello from Client 2"));
            Thread client3 = new Thread(() -> connectClient("客户端3", "Hello from Client 3"));
            
            // 几乎同时启动客户端
            client1.start();
            Thread.sleep(500); // 稍微错开时间
            client2.start();
            Thread.sleep(500);
            client3.start();
            
            // 等待所有客户端完成
            client1.join();
            client2.join();
            client3.join();
            
            // 等待一段时间
            Thread.sleep(2000);
            
            // 停止服务器
            server.stop();
            
        } catch (InterruptedException e) {
            System.err.println("演示被中断: " + e.getMessage());
        }
    }
    
    // ==================== 辅助方法 ====================
    
    /**
     * 连接客户端并发送消息
     */
    private static void connectClient(String clientName, String message) {
        try (Socket socket = new Socket("localhost", PORT);
             PrintWriter writer = new PrintWriter(socket.getOutputStream(), true);
             BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()))) {
            
            System.out.println("   " + clientName + " 连接成功");
            
            // 发送消息
            writer.println(message);
            System.out.println("   " + clientName + " 发送: " + message);
            
            // 读取响应
            String response = reader.readLine();
            System.out.println("   " + clientName + " 收到: " + response);
            
            // 模拟处理时间
            Thread.sleep(3000);
            System.out.println("   " + clientName + " 处理完成");
            
        } catch (IOException | InterruptedException e) {
            System.err.println("   " + clientName + " 异常: " + e.getMessage());
        }
    }
    
    // ==================== 内部类：单线程服务器 ====================
    
    /**
     * 单线程BIO服务器
     * 特点：可以依次接受多个连接，但处理时会阻塞accept()
     */
    private static class SingleThreadServer {
        private final int port;
        private ServerSocket serverSocket;
        private volatile boolean running = false;
        
        public SingleThreadServer(int port) {
            this.port = port;
        }
        
        public void start() {
            try {
                serverSocket = new ServerSocket(port);
                running = true;
                
                System.out.println("单线程服务器启动，端口: " + port);
                System.out.println("特点：可以依次接受多个连接，但处理时会阻塞accept()");
                
                // 单线程处理所有连接
                while (running) {
                    try {
                        System.out.println("   等待客户端连接...");
                        System.out.println("   注意：accept()会阻塞，直到有客户端连接");
                        
                        // accept()阻塞在这里，等待客户端连接
                        Socket clientSocket = serverSocket.accept();
                        System.out.println("   接受新连接: " + clientSocket.getInetAddress());
                        
                        // 直接处理客户端（会阻塞accept()，无法接受新连接）
                        handleClient(clientSocket);
                        
                        System.out.println("   客户端处理完成，继续等待下一个连接");
                        
                    } catch (IOException e) {
                        if (running) {
                            System.err.println("   服务器异常: " + e.getMessage());
                        }
                    }
                }
                
            } catch (IOException e) {
                System.err.println("单线程服务器启动失败: " + e.getMessage());
            }
        }
        
        private void handleClient(Socket clientSocket) {
            try (BufferedReader reader = new BufferedReader(
                    new InputStreamReader(clientSocket.getInputStream()));
                 PrintWriter writer = new PrintWriter(clientSocket.getOutputStream(), true)) {
                
                System.out.println("   开始处理客户端: " + clientSocket.getInetAddress());
                System.out.println("   注意：此时accept()被阻塞，无法接受新连接");
                System.out.println("   其他客户端需要等待这个客户端处理完成");
                
                String message;
                while ((message = reader.readLine()) != null) {
                    System.out.println("   收到消息: " + message);
                    
                    // 发送响应
                    String response = "单线程服务器响应: " + message;
                    writer.println(response);
                    System.out.println("   发送响应: " + response);
                    
                    // 模拟处理时间
                    Thread.sleep(2000);
                    System.out.println("   客户端处理完成");
                    break; // 只处理一条消息
                }
                
            } catch (IOException | InterruptedException e) {
                System.err.println("   处理客户端异常: " + e.getMessage());
            } finally {
                try {
                    clientSocket.close();
                } catch (IOException e) {
                    // 忽略关闭异常
                }
            }
        }
        
        public void stop() {
            running = false;
            if (serverSocket != null) {
                try {
                    serverSocket.close();
                    System.out.println("   单线程服务器已停止");
                } catch (IOException e) {
                    System.err.println("   停止服务器异常: " + e.getMessage());
                }
            }
        }
    }
    
    // ==================== 内部类：多线程服务器 ====================
    
    /**
     * 多线程BIO服务器
     * 优势：accept()和处理客户端分离
     */
    private static class MultiThreadServer {
        private final int port;
        private ServerSocket serverSocket;
        private ExecutorService executor;
        private volatile boolean running = false;
        
        public MultiThreadServer(int port) {
            this.port = port;
        }
        
        public void start() {
            try {
                serverSocket = new ServerSocket(port);
                executor = Executors.newCachedThreadPool();
                running = true;
                
                System.out.println("多线程服务器启动，端口: " + port);
                System.out.println("优势：accept()和处理客户端分离，可以同时接受多个连接");
                
                // 启动监听线程
                new Thread(() -> {
                    while (running) {
                        try {
                            System.out.println("   等待客户端连接...");
                            System.out.println("   accept()可以持续接受新连接");
                            
                            // accept()阻塞在这里，但不会影响其他客户端处理
                            Socket clientSocket = serverSocket.accept();
                            System.out.println("   接受新连接: " + clientSocket.getInetAddress());
                            
                            // 为新连接创建独立线程处理
                            executor.submit(() -> handleClient(clientSocket));
                            
                        } catch (IOException e) {
                            if (running) {
                                System.err.println("   服务器异常: " + e.getMessage());
                            }
                        }
                    }
                }).start();
                
            } catch (IOException e) {
                System.err.println("多线程服务器启动失败: " + e.getMessage());
            }
        }
        
        private void handleClient(Socket clientSocket) {
            try (BufferedReader reader = new BufferedReader(
                    new InputStreamReader(clientSocket.getInputStream()));
                 PrintWriter writer = new PrintWriter(clientSocket.getOutputStream(), true)) {
                
                System.out.println("   线程" + Thread.currentThread().getName() + " 开始处理客户端: " + clientSocket.getInetAddress());
                System.out.println("   注意：此线程的阻塞不会影响accept()接受新连接");
                
                String message;
                while ((message = reader.readLine()) != null) {
                    System.out.println("   收到消息: " + message);
                    
                    // 发送响应
                    String response = "多线程服务器响应: " + message;
                    writer.println(response);
                    System.out.println("   发送响应: " + response);
                    
                    // 模拟处理时间
                    Thread.sleep(2000);
                    System.out.println("   客户端处理完成");
                    break; // 只处理一条消息
                }
                
            } catch (IOException | InterruptedException e) {
                System.err.println("   处理客户端异常: " + e.getMessage());
            } finally {
                try {
                    clientSocket.close();
                } catch (IOException e) {
                    // 忽略关闭异常
                }
            }
        }
        
        public void stop() {
            running = false;
            if (executor != null) {
                executor.shutdown();
            }
            if (serverSocket != null) {
                try {
                    serverSocket.close();
                    System.out.println("   多线程服务器已停止");
                } catch (IOException e) {
                    System.err.println("   停止服务器异常: " + e.getMessage());
                }
            }
        }
    }
} 